package com.store.orm.mysql.crud.impl;

import com.store.orm.mysql.MySQLUtil;
import com.store.orm.mysql.crud.Select;
import com.store.orm.mysql.crud.filter.Filtration;
import com.store.orm.mysql.handler.ListRSHandler;
import com.store.orm.util.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;

import static com.store.orm.common.KeyWord.*;

/**
 * @author 宫静雨
 * @version 1.0
 */
public class MySQLSelect implements Select {
    private static final Logger logger = LoggerFactory.getLogger(MySQLSelect.class);
    private MySQLUtil UTIL;

    public MySQLSelect(MySQLUtil UTIL) {
        this.UTIL = UTIL;
    }

    private String condition(Set<String> keys) {
        StringBuilder sb = new StringBuilder();
        if (keys.size() != 0) {
            sb.append(WHERE);
            keys.forEach(key -> sb.append(key).append(EQUAL_TO).append(QUESTION).append(AND));
            sb.delete(sb.lastIndexOf(AND), sb.length());
        }
        return sb.toString();
    }

    private <T> List<T> execute(Class<T> cls, Map<String, Object> map) {
        Field[] fields = cls.getDeclaredFields();
        String tableName = UTIL.getTableName(cls);
        String prefix = UTIL.prefix(tableName, fields);
        String condition = condition(map.keySet());
        String sql = prefix + condition;
        Connection connection = UTIL.getConnection();
        try {
            PreparedStatement ps = connection.prepareStatement(sql);
            List<Object> list = new ArrayList<>(map.values());
            for (int i = 0; i < list.size(); i++) {
                ps.setObject(i + 1, list.get(i));
            }
            ResultSet resultSet = ps.executeQuery();
            if (UTIL.isLogged()) {
                logger.info(">>> {}", sql);
                logger.info("<<< {}", list);
            }
            return new ListRSHandler(UTIL).handler(resultSet, cls);
        } catch (SQLException e) {
            logger.error("查询数据时: {}", e.getMessage());
        }
        return null;
    }

    @Override
    public <T> List<T> find(T t) {
        Class<T> cls = (Class<T>) t.getClass();
        Map<String, Object> map = UTIL.parseTToMap(t);
        return execute(cls, map);
    }

    @Override
    public <T> List<T> find(Class<T> cls, String json) {
        Map<String, Object> map = UTIL.parseJsonToMap(json);
        return execute(cls, map);
    }

    @Override
    public <T> List<T> find(Class<T> cls, LinkedHashMap<String, Object> map) {
        return execute(cls, map);
    }

    @Override
    public <T> List<T> find(Class<T> cls, Filtration filter) {
        String tableName = UTIL.getTableName(cls);
        Field[] fields = cls.getDeclaredFields();
        String prefix = UTIL.prefix(tableName, fields);
        String sql = prefix + filter.get();
        Connection connection = UTIL.getConnection();
        try {
            PreparedStatement ps = connection.prepareStatement(sql);
            ResultSet resultSet = ps.executeQuery();
            if (UTIL.isLogged()) {
                logger.info(">>> {}", sql);
            }
            return new ListRSHandler(UTIL).handler(resultSet, cls);
        } catch (SQLException e) {
            logger.error("执行SQL出现错误: {}", e.getMessage());
        }
        return null;
    }

    @Override
    public <T> List<T> find(Class<T> cls, Filtration filter, String... fields) {
        String tableName = UTIL.getTableName(cls);
        StringBuilder sb = new StringBuilder();
        sb.append(SELECT);
        for (int i = 0; i < fields.length; i++) {
            sb.append(fields[i]);
            if (i != fields.length - 1) {
                sb.append(COMMA);
            }
        }
        sb.append(FROM).append(tableName);
        String s = filter.get();
        if (StringUtil.isBlank(s)) {
            sb.append(s);
        }
        String sql = sb.toString();
        Connection connection = UTIL.getConnection();
        try {
            PreparedStatement ps = connection.prepareStatement(sql);
            ResultSet resultSet = ps.executeQuery();
            if (UTIL.isLogged()) {
                logger.info(">>> {}", sql);
            }
            return new ListRSHandler(UTIL).handler(resultSet, cls);
        } catch (SQLException e) {
            logger.error("执行SQL出现错误: {}", e.getMessage());
        }
        return null;
    }
}